<template>
    <el-select
      ref="selectRef"
      v-bind="$attrs"
      v-model="selectedValue"
      @visible-change="handleVisibleChange"
      @change="handleChange"
    >
      <el-option
        v-for="item in options"
        :key="getOptionKey(item)"
        :label="getOptionLabel(item)"
        :value="getOptionValue(item)"
        :disabled="item.disabled"
      />
      <template #footer v-if="showLoading">
        <div class="infinite-scroll-loading">
          <el-icon v-if="loading" class="is-loading">
            <Loading />
          </el-icon>
          <span>{{ loading ? '加载中...' : '滚动加载更多' }}</span>
        </div>
      </template>
    </el-select>
  </template>
  
  <script setup>
  import { ref, watch, onMounted, onUnmounted, computed } from 'vue'
  import { Loading } from '@element-plus/icons-vue'
  
  const props = defineProps({
    modelValue: { // 兼容 v-model
      type: [String, Number, Boolean, Array, Object],
      default: undefined
    },
    options: {
      type: Array,
      default: () => []
    },
    loading: {
      type: Boolean,
      default: false
    },
    hasMore: {
      type: Boolean,
      default: false
    },
    optionKey: {
      type: [String, Function],
      default: 'value'
    },
    optionLabel: {
      type: [String, Function],
      default: 'label'
    },
    optionValue: {
      type: [String, Function],
      default: 'value'
    },
    loadingText: {
      type: String,
      default: '加载中...'
    },
    loadMoreText: {
      type: String,
      default: '滚动加载更多'
    }
  })
  
  const emit = defineEmits([
    'update:modelValue',
    'change',
    'load-more'
  ])
  
  const selectRef = ref(null)
  const selectedValue = ref(props.modelValue)
  let scrollEl = null
  
  // 计算属性：是否显示加载状态
  const showLoading = computed(() => props.hasMore || props.loading)
  
  // 获取选项唯一key
  const getOptionKey = (item) => {
    return typeof props.optionKey === 'function' 
      ? props.optionKey(item) 
      : item[props.optionKey]
  }
  
  // 获取选项显示文本
  const getOptionLabel = (item) => {
    return typeof props.optionLabel === 'function' 
      ? props.optionLabel(item) 
      : item[props.optionLabel]
  }
  
  // 获取选项值
  const getOptionValue = (item) => {
    return typeof props.optionValue === 'function' 
      ? props.optionValue(item) 
      : item[props.optionValue]
  }
  
  // 处理值变化
  const handleChange = (value) => {
    emit('update:modelValue', value)
    emit('change', value)
  }
  
  // 处理下拉框显示状态变化
  const handleVisibleChange = (visible) => {
    if (visible) {
      // 延迟确保下拉菜单已渲染
      setTimeout(setupScrollListener, 150)
    } else {
      removeScrollListener()
    }
  }
  
  // 设置滚动监听
  const setupScrollListener = () => {
    
    if (!selectRef.value) return
  
    // 通过组件实例获取下拉容器
    const popper = selectRef.value.popperRef
    
    if (!popper) return
  
    // 查找滚动元素
    scrollEl = popper.querySelector('.el-select-dropdown__wrap')
    
    if (scrollEl) {
      scrollEl.addEventListener('scroll', handleScroll)
    }
  }
  
  // 移除滚动监听
  const removeScrollListener = () => {
    if (scrollEl) {
      scrollEl.removeEventListener('scroll', handleScroll)
      scrollEl = null
    }
  }
  
  // 处理滚动事件
  const handleScroll = () => {
    if (!scrollEl || props.loading || !props.hasMore) return
  
    const { scrollTop, scrollHeight, clientHeight } = scrollEl
    // 滚动到底部时触发加载更多 (增加5px缓冲)
    if (scrollHeight - scrollTop <= clientHeight + 5) {
      emit('load-more')
    }
  }
  
  // 监听modelValue变化
  watch(() => props.modelValue, (val) => {
    selectedValue.value = val
  })
  
  // 组件卸载时清理
  onUnmounted(() => {
    removeScrollListener()
  })
  </script>
  
  <style scoped>
  .infinite-scroll-loading {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 8px 0;
    color: var(--el-text-color-secondary);
    font-size: 12px;
  }
  
  .infinite-scroll-loading .el-icon {
    margin-right: 6px;
    animation: rotating 2s linear infinite;
  }
  
  @keyframes rotating {
    from {
      transform: rotate(0deg);
    }
    to {
      transform: rotate(360deg);
    }
  }
  </style>
